package views;

import controllers.Controller;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import javax.swing.border.CompoundBorder;

/*
 * TODO: hace un enumerado para los tipos de celdas(Modificable, ModificableDeAyuda etc)
 * y hacer metodos que pinten una celda segun un parametro de tal enumerado
 *
 * TODO: crear estados de juego para la grafica para no mostrar botones innecesarios
 *
 * TODO IMPORTANTE: al iniciar nueva partida pedir el nivel(lista desplegable estaria bueno)
 *
 */
public class WindowGraphics extends Graphics
{
    public WindowGraphics(Controller controller)
    {
        super(controller);
    }

    public void init()
    {
        InitFrame();
        InitGrid();
        InitButton();

        panelBoard.setVisible(true);
        frame.setVisible(true);
        inicialState();
    }

    public void draw()
    {
        if (matrix != null)
            for (int i = 0; i < 9; i++)
                for (int j = 0; j < 9; j++)
                    setValue(i, j, matrix[i][j]);
    }

    public void update()
    {
        draw();
    }

    public void updateNumber() {}

    public String getBestTimeName()
    {
        // TODO Auto-generated method stub
        return JOptionPane.showInputDialog("Ingrese su nombre (no se permiten numeros)");
    }

    public void pressent(String string)
    {
        JOptionPane.showMessageDialog(null, string);
    }

    public void setMatrix(int[][] matrix)
    {
        this.matrix = matrix;
    }

    public void hideBoard()
    {
        panelBoard.setVisible(false);
    }

    public void showBoard()
    {
        panelBoard.setVisible(true);
    }

    //TODO: modularizar y me parece que se le esta dando una responsabilidad que no
    //      es de solo mostrar a la vista!
    //BUG: si  ya no quiere ayuda queda todo pintado, corregir eso podria ser con un metodo que haga lo contrario
    public void getHelp()
    {
        for (int i = 0; i < 9; i++)
            for (int j = 0; j < 9; j++)
            {
                JTextField actual = (JTextField) board[i][j];
                int value =  getInputValueOnBoar(i, j);

                if (controller.help(i, j, value))
                {
                    actual.setBackground(Color.GREEN);
                    actual.setEditable(false);
                }
                else
                {
                    actual.setBackground(Color.RED);
                    actual.setForeground(Color.white);
                }
            }
    }

    public void setTime(String time)
    {
        timeLabel.setText(time);
    }

    private void InitFrame()
    {
        frame = new JFrame();
        frame.setBounds(200, 200, 800, 600);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    private void InitGrid()
    {
        board = new Object[9][9];

        panelBoard = new JPanel(new GridLayout(10, 9));
        frame.getContentPane().add(panelBoard, BorderLayout.CENTER);

        Font font = new Font("Arial", Font.PLAIN, 20);
        SudokuKeyListener listener = new SudokuKeyListener();

        for (int i = 0; i < 9; i++)
            for (int j = 0; j < 9; j++)
                addSudokuField(i, j, listener, font);
    }

    private void addSudokuField(int i, int j, KeyListener listener, Font font)
    {
        SudokuTextField jText = new SudokuTextField(i, j);

        jText.addKeyListener(listener);
        jText.setBounds(0, 0, 10, 10);
        jText.setBackground(Color.YELLOW);
        jText.setFont(font);
        jText.setOpaque(true);
        jText.setHorizontalAlignment(JTextField.CENTER);

        setBorder(jText, i, j);

        board[i][j] = jText;
        panelBoard.add(jText);
    }

    //TODO: mejorar!
    private void setBorder(SudokuTextField jText, int i, int j)
    {
        jText.setBorder(new CompoundBorder(
                            BorderFactory.createMatteBorder(0,  0, 0, 0, Color.DARK_GRAY),
                            BorderFactory.createMatteBorder(0, 0, 10, 10, Color.GRAY)));

        if (j == 2 || j == 5 || j == 8)
        {
            jText.setBorder(new CompoundBorder(
                                BorderFactory.createMatteBorder(0, 0, 0, 10, Color.DARK_GRAY),
                                BorderFactory.createMatteBorder(0, 0, 10, 0, Color.GRAY)));
        }

        if (i == 2 || i == 5 || i == 8)
        {
            jText.setBorder(new CompoundBorder(
                                BorderFactory.createMatteBorder(0, 0, 10,  0, Color.DARK_GRAY),
                                BorderFactory.createMatteBorder(0, 0, 0, 10, Color.GRAY)));
        }

        if (((i == 2 || i == 5 || i == 8) && (j == 2 || j == 5 || j == 8)))
        {
            jText.setBorder(new CompoundBorder(
                                BorderFactory.createMatteBorder(0, 0, 10,  10, Color.DARK_GRAY),
                                BorderFactory.createMatteBorder(0, 0, 0, 0, Color.GRAY)));
        }

        if (j == 0)
        {
            jText.setBorder(new CompoundBorder(
                                BorderFactory.createMatteBorder(0, 10, 0,  0, Color.DARK_GRAY),
                                BorderFactory.createMatteBorder(0, 0, 10, 10, Color.GRAY)));
        }

        if (j == 0 && (i == 2 || i == 5 || i == 8))
        {
            jText.setBorder(new CompoundBorder(
                                BorderFactory.createMatteBorder(0, 10, 10,  0, Color.DARK_GRAY),
                                BorderFactory.createMatteBorder(0, 0, 0, 10, Color.GRAY)));
        }

        if (i == 0)
        {
            jText.setBorder(new CompoundBorder(
                                BorderFactory.createMatteBorder(10, 0, 0,  0, Color.DARK_GRAY),
                                BorderFactory.createMatteBorder(0, 0, 10, 10, Color.GRAY)));
        }

        if (i == 0 && j == 0)
        {
            jText.setBorder(new CompoundBorder(
                                BorderFactory.createMatteBorder(10, 10, 0,  0, Color.DARK_GRAY),
                                BorderFactory.createMatteBorder(0, 0, 10, 10, Color.GRAY)));
        }

        if (i == 0 && (j == 2 || j == 5 || j == 8))
        {
            jText.setBorder(new CompoundBorder(
                                BorderFactory.createMatteBorder(10, 0, 0,  10, Color.DARK_GRAY),
                                BorderFactory.createMatteBorder(0, 0, 10, 0, Color.GRAY)));
        }
    }

    private void InitButton()
    {
        botonera = new JPanel();
        frame.getContentPane().add(botonera, BorderLayout.SOUTH);

        timeLabel = new JLabel("");
        botonera.add(timeLabel);

        config = new ButtonGroup();
        conf1 = new JRadioButton(UNO, true);
        conf2 = new JRadioButton(DOS, false);
        conf3 = new JRadioButton(TRES, false);
        config.add(conf1);
        config.add(conf2);
        config.add(conf3);
        botonera.add(conf1);
        botonera.add(conf2);
        botonera.add(conf3);

        btnNuevaPartida = new JButton();
        botonera.add(btnNuevaPartida);
        btnNuevaPartida.setAction(new InitConfig(controller));

        btnInicio = new JButton();
        botonera.add(btnInicio);
        btnInicio.setAction(new InitGame(controller));

        btnDetener = new JButton();
        botonera.add(btnDetener);
        btnDetener.setAction(new Stop(controller));

        btnVerificar = new JButton();
        botonera.add(btnVerificar);
        btnVerificar.setAction(new Verify(controller));

        btnPausa = new JButton();
        botonera.add(btnPausa);
        btnPausa.setAction(new Pause(controller));

        btnContinuar = new JButton();
        botonera.add(btnContinuar);
        btnContinuar.setAction(new Resume(controller));

        btnMeRindo = new JButton();
        botonera.add(btnMeRindo);
        btnMeRindo.setAction(new MeRindo(controller));

        btnTop10 = new JButton();
        botonera.add(btnTop10);
        btnTop10.setAction(new Top10(controller));

        btnVaciar = new JButton();
        botonera.add(btnVaciar);
        btnVaciar.setAction(new Vaciar(controller));

        btnHelp = new JButton();
        botonera.add(btnHelp);
        btnHelp.setAction(new Help(controller));
        
        btnReglas = new JButton();
        botonera.add(btnReglas);
        btnReglas.setAction(new Reglas(controller));
        btnReglas.setVisible(true);
    }

    private void setValue(int x, int y, int value)
    {
        JTextField actual = (JTextField) board[x][y];

        if (value != 0)
        {
            actual.setEditable(false);
            actual.setBackground(Color.ORANGE);
            actual.setForeground(Color.BLACK);
            actual.setText(String.valueOf(value));
        }
        else
        {
            actual.setEditable(true);
            actual.setBackground(Color.YELLOW);
            actual.setForeground(Color.RED);
            actual.setText("");
        }
    }

    private int getInputValueOnBoar(int x, int y)
    {
        JTextField actual = (JTextField) board[x][y];
        String input = actual.getText();

        return getValue(input);
    }

    /*
     *
     *
     *
     * TODO: ver/investigar donde deberian ir estos actions
     *
     *
     */
    private class Pause extends AbstractAction
    {
        private static final long serialVersionUID = 1L;
        private Controller controller;

        public Pause(Controller controller)
        {
            super(PAUSA);
            this.controller = controller;
        }

        public void actionPerformed(ActionEvent e)
        {
            controller.pause();
        }
    }

    private class Verify extends AbstractAction
    {
        private static final long serialVersionUID = 1L;
        private Controller controller;

        public Verify(Controller controller)
        {
            super(VERIFICAR);
            this.controller = controller;
        }

        public void actionPerformed(ActionEvent e)
        {
            controller.verify();
        }
    }

    private class InitConfig extends AbstractAction
    {
        private static final long serialVersionUID = 1L;
        private Controller controller;

        public InitConfig(Controller controller)
        {
            super(NUEVAPARTIDA);
            this.controller = controller;
        }

        public void actionPerformed(ActionEvent e)
        {
            controller.initConfig();
        }
    }


    private class InitGame extends AbstractAction
    {
        private static final long serialVersionUID = 1L;
        private Controller controller;

        public InitGame(Controller controller)
        {
            super(INICIAR);
            this.controller = controller;
        }

        public void actionPerformed(ActionEvent e)
        {
            controller.initNewGame(getConfig());
        }
    }

    private class Stop extends AbstractAction
    {
        private static final long serialVersionUID = 1L;
        private Controller controller;

        public Stop(Controller controller)
        {
            super(DETENER);
            this.controller = controller;
        }
        public void actionPerformed(ActionEvent e)
        {
            controller.stop();
        }
    }

    private class Resume extends AbstractAction
    {
        private static final long serialVersionUID = 1L;
        private Controller controller;

        public Resume(Controller controller)
        {
            super(CONTINUAR);
            this.controller = controller;
        }
        public void actionPerformed(ActionEvent e)
        {
            controller.resume();
        }
    }

    private class Top10 extends AbstractAction
    {
        private static final long serialVersionUID = 1L;
        //private Controller controller;

        public Top10(Controller controller)
        {
            super(TOP10);
            //this.controller = controller;
        }
        public void actionPerformed(ActionEvent e)
        {
            controller.top();
        }
    }

    private class MeRindo extends AbstractAction
    {
        private static final long serialVersionUID = 1L;
        private Controller controller;

        public MeRindo(Controller controller)
        {
            super(MERINDO);
            this.controller = controller;
        }
        public void actionPerformed(ActionEvent e)
        {
            controller.meRindo();
        }
    }
    
    private class Reglas extends AbstractAction
    {

        private static final long serialVersionUID = 1L;
        private Controller controller;

        public Reglas(Controller controller)
        {
            super(REGLAS);
            this.controller = controller;
        }
        public void actionPerformed(ActionEvent e)
        {
        	controller.mostrarReglas();
    	}
        	
    }

    private class Vaciar extends AbstractAction
    {
        private static final long serialVersionUID = 1L;
        private Controller controller;

        public Vaciar(Controller controller)
        {
            super(VACIAR);
            this.controller = controller;
        }
        public void actionPerformed(ActionEvent e)
        {
            controller.vaciar();
        }
    }

    private class Help extends AbstractAction
    {

        private static final long serialVersionUID = 1L;
        private Controller controller;

        public Help(Controller controller)
        {
            super(AYUDA);
            this.controller = controller;
        }
        public void actionPerformed(ActionEvent e)
        {
            controller.globalHelp();
        }
    }

    /*
     *TODO: el listener solo deberia decirle al controlador aca se preciono esta tecla
     *  en realidad decir aca(x,y) se inserto esta cadena y el controlador debe validar
     *  esos datos(si es un numero o no) y segun eso decirle a la vista actualiza en la vista
     *  en la pos(x,y) con este numero y en caso de entrada invalida mostrar cartelito con pressent
     *
     *TODO 2: separar los listener de la vista
     */
    private class SudokuKeyListener implements KeyListener
    {
        public void keyReleased(KeyEvent e)
        {
            SudokuTextField jText = (SudokuTextField) e.getSource();

            int value = getValue(jText.getText());
            int x     = jText.getColumn();
            int y     = jText.getRow();

            controller.setValueOnBoard(x, y, value);
        }

        public void keyTyped(KeyEvent e)
        {
            control(e);
        }

        public void keyPressed(KeyEvent e) {}


        private void control(KeyEvent e) // funcion que verifica que se ingrese un numero entre 1 y 9 inclusive
        {
            SudokuTextField jText = (SudokuTextField) e.getSource();
            char c = e.getKeyChar();

            if (!(Character.isDigit(c) && Character.getNumericValue(c) != 0)) // si no es un digito o es un 0, lo ignoro
            {
                e.consume();
                pressent("ERROR: SOLO PUEDE INGRESAR NUMEROS ENTRE 1 Y 9");
            }
            else // si est� en el rango permitido
            {
                jText.setText(Character.toString(c));  //para que se cambie cuando haga foco y no tenga que borrar para modificar el valor
                e.setKeyChar('\0'); // restringiendo 1 solo valor
            }
        }
    }

    private class SudokuTextField extends JTextField
    {
        private static final long serialVersionUID = 1L;
        private int x;
        private int y;

        public SudokuTextField(int x, int y)
        {
            super("");
            this.x = x;
            this.y = y;
        }

        public int getColumn()
        {
            return x;
        }

        public int getRow()
        {
            return y;
        }
    }

    //TODO: esto no estar existir aca sino mas bien en el controlador
    private int getValue(String text)
    {
        int result;

        try
        {
            result = Integer.parseInt(text.trim());
        }
        catch (NumberFormatException e)
        {
            result = 0;
        }

        return result;
    }

    private int getConfig()
    {
        int configuracion  = 0;
        if (conf1.isSelected())
            configuracion = 1;
        if (conf2.isSelected())
            configuracion = 2;
        if (conf3.isSelected())
            configuracion = 3;

        return configuracion;
    }

    //Estados

    public void configState()
    {

        timeLabel.setVisible(false);
        conf1.setVisible(true);
        conf2.setVisible(true);
        conf3.setVisible(true);
        btnTop10.setVisible(false);
        btnMeRindo.setVisible(false);
        btnPausa.setVisible(false);
        btnVerificar.setVisible(false);
        btnInicio.setVisible(true);
        btnDetener.setVisible(false);
        btnContinuar.setVisible(false);
        btnVaciar.setVisible(false);
        btnHelp.setVisible(false);
        btnNuevaPartida.setVisible(false);

    }


    public void inicialState()
    {

        timeLabel.setVisible(false);
        conf1.setVisible(false);
        conf2.setVisible(false);
        conf3.setVisible(false);
        btnTop10.setVisible(true);
        btnMeRindo.setVisible(false);
        btnPausa.setVisible(false);
        btnVerificar.setVisible(false);
        btnInicio.setVisible(false);
        btnDetener.setVisible(false);
        btnContinuar.setVisible(false);
        btnVaciar.setVisible(false);
        btnHelp.setVisible(false);
        btnNuevaPartida.setVisible(true);

    }


    public void jugandoState()
    {

        timeLabel.setVisible(true);
        conf1.setVisible(false);
        conf2.setVisible(false);
        conf3.setVisible(false);
        btnTop10.setVisible(false);
        btnMeRindo.setVisible(true);
        btnPausa.setVisible(true);
        btnVerificar.setVisible(true);
        btnInicio.setVisible(false);
        btnDetener.setVisible(true);
        btnContinuar.setVisible(false);
        btnVaciar.setVisible(true);
        btnHelp.setVisible(true);
        btnNuevaPartida.setVisible(false);

    }


    public void pausaState()
    {

        timeLabel.setVisible(true);
        conf1.setVisible(false);
        conf2.setVisible(false);
        conf3.setVisible(false);
        btnTop10.setVisible(false);
        btnMeRindo.setVisible(false);
        btnPausa.setVisible(false);
        btnVerificar.setVisible(false);
        btnInicio.setVisible(false);
        btnDetener.setVisible(false);
        btnContinuar.setVisible(true);
        btnVaciar.setVisible(false);
        btnHelp.setVisible(false);
        btnNuevaPartida.setVisible(false);

    }


    public void rendidoState()
    {

        timeLabel.setVisible(true);
        conf1.setVisible(false);
        conf2.setVisible(false);
        conf3.setVisible(false);
        btnTop10.setVisible(true);
        btnMeRindo.setVisible(false);
        btnPausa.setVisible(false);
        btnVerificar.setVisible(false);
        btnInicio.setVisible(false);
        btnDetener.setVisible(false);
        btnContinuar.setVisible(false);
        btnVaciar.setVisible(false);
        btnHelp.setVisible(false);
        btnNuevaPartida.setVisible(true);

    }


    private JFrame frame;
    private JPanel panelBoard;
    private JPanel botonera;
    private JLabel timeLabel;

    private ButtonGroup config;
    private JRadioButton conf1;
    private JRadioButton conf2;
    private JRadioButton conf3;
    private JButton btnTop10;
    private JButton btnMeRindo;
    private JButton btnPausa;
    private JButton btnVerificar;
    private JButton btnInicio;
    private JButton btnDetener;
    private JButton btnContinuar;
    private JButton btnVaciar;
    private JButton btnHelp;
    private JButton btnNuevaPartida;
    private JButton btnReglas;

    private Object[][] board;

    private static final String UNO       = "FACIL";
    private static final String DOS       = "INTERMEDIO";
    private static final String TRES      = "DIFICIL";
    private static final String NUEVAPARTIDA = "NUEVAPARTIDA";
    private static final String INICIAR   = "INICIAR";
    private static final String DETENER   = "DETENER";
    private static final String PAUSA     = "PAUSA";
    private static final String CONTINUAR = "CONTINUAR";
    private static final String VERIFICAR = "VERIFICAR";
    private static final String MERINDO   = "ME RINDO";
    private static final String TOP10     = "TOP10";
    private static final String VACIAR    = "VACIAR";
    private static final String AYUDA     = "AYUDA";
    private static final String REGLAS    = "REGLAS";
	@Override
	
	
	public void mostrarPuntajes(String[] topTen) {
		String results="";
		for(int i=0; i<10; i++)
			results+=topTen[i]+"\n";
		JOptionPane.showMessageDialog(null, results);
			
		
	}

}
